from cStringIO import StringIO
from django.http import HttpResponse, HttpResponseRedirect, Http404,\
    HttpResponseForbidden
from django.shortcuts import render_to_response, get_object_or_404

from django.utils.decorators import decorator_from_middleware
from django.db.models import Q

from szachy.models import Game, FBUser
from szachy.forms import GameForm, SideChoiceForm, MoveForm
from django.core.urlresolvers import reverse
from django.template.context import RequestContext
from szachy.chess import Coord, MATE, STALEMATE, WHITE
from django.utils import simplejson
from django.contrib.sites.models import Site
import facebookdj
from django.core.paginator import Paginator
from django.conf import settings
import urllib
from django.template.loader import render_to_string
from facebook.rest import FacebookError


MY_FB_APP_URL = 'http://apps.facebook.com/%s/' % settings.FACEBOOK_APP_NAME


CLASSES = {
    'R': 'rl',
    'r': 'rd',
    'N': 'nl',
    'n': 'nd',
    'B': 'bl',
    'b': 'bd',
    'K': 'kl',
    'k': 'kd',
    'Q': 'ql',
    'q': 'qd',
    'P': 'pl',
    'p': 'pd',
    '.': ''
}


@facebookdj.require_login()
def index(request):
    '''  
    args = dict(client_id=settings.FACEBOOK_API_KEY, redirect_uri='http://'+Site.objects.get_current().domain+reverse('canvas'), scope='user_activities,friends_activities')
    return request.graph.redirect("https://graph.facebook.com/oauth/authorize?" +
                urllib.urlencode(args))
    '''
    me = FBUser.objects.get_current()
    request.rest.dashboard.setCount(me.get_wait_action_count(), me.id)
    return render_to_response('szachy/index.html', {'me': me}, context_instance=RequestContext(request))


@facebookdj.require_login()
def players(request, page=1):
    paginator = Paginator(FBUser.objects.order_by('-ranking'), 5)
    page = paginator.page(page)
    me = FBUser.objects.get_current()
    return render_to_response('szachy/players.html', {'page': page, 'me': me}, context_instance=RequestContext(request))

@facebookdj.require_login()
def invite_to_game(request, player_id, next=''):
    '''
    send invite, to new game
    '''
    game = Game.objects.play(request.graph.uid, player_id)
    return HttpResponseRedirect(reverse('game', kwargs={'game_id': game.id}))


@facebookdj.require_login()
def initiate_match(request):
    for opponent_id in request.POST.getlist('ids[]'):
        Game.objects.play(request.graph.uid, opponent_id)
        request.rest.dashboard.incrementCount(int(opponent_id))
        try:    
            request.rest.dashboard.publishActivity({'message': '{*actor*} start new game with @:%d' % int(opponent_id), 'action_link': {'text': 'Game url', 'href': 'http://www.facebook.com/iszachy/game/1'}})
        except FacebookError:
            # if it is a new player, activity publishing make error
            pass
        
    return request.graph.redirect(MY_FB_APP_URL)

@facebookdj.require_login()
def decline_match(request, game_id):
    game = get_object_or_404(Game, id=game_id)
 
    if not int(request.graph.uid) in (game.p1_id, game.p2_id):
        raise HttpResponseForbidden('It is not your match!')
    
    # decrement players who do not select side or my decision
    if game.p1_state == Game.PLAYER_UNKNOWN_SIDE:
        request.rest.dashboard.decrementCount(game.p1.id)
    if game.p2_state == Game.PLAYER_UNKNOWN_SIDE:
        request.rest.dashboard.decrementCount(game.p2.id)
    
    game.delete()
    return HttpResponseRedirect(reverse('canvas'))

@facebookdj.require_login()
def select_side(request, game_id, side):
    game = get_object_or_404(Game, id=game_id)
    me = FBUser.objects.get_current()
    if game.p1 == me:
        if game.p2_state != side:
            game.p1_state = side
        else:
            raise Exception('Make message for selecting the same side')
    elif game.p2 == me:
        if game.p1_state != side:
            game.p2_state = side
        else:
            raise Exception('Make message for selecting the same side')
    else:
        raise HttpResponseForbidden('You cannot select side for not your game!')
    game.try_start_game()
    game.save()
    
    return HttpResponseRedirect(reverse('game', kwargs={'game_id': game_id}))
    
@facebookdj.require_login()
def make_move(request, game_id):
    game = get_object_or_404(Game, id=game_id)
    me = FBUser.objects.get_current()
    my_move = (me.id == game.current_move)
    
    form = None
    if my_move:
        if request.method == 'POST':
            form = MoveForm(request.POST, game)
            if form.is_valid():
                form.save()

                request.rest.dashboard.incrementCount(game.current_move.id)
                request.rest.dashboard.decrementCount(me.id)
                if request.is_ajax():
                    return get_chessboard(request, game_id)
                return HttpResponseRedirect(reverse('game', kwargs={'game_id': game.id}))
            elif request.is_ajax():
                return HttpResponse(simplejson.dumps({'errors': str(form.errors['your_move'])}))
        else:
            form = MoveForm()

def get_moves(game):
    f = StringIO()
    game.game.export_pgn(f)
    f.seek(0)
    return f.read()

def get_chessboard(request, game_id, black_on_bottom=None):
    
    game = get_object_or_404(Game, id=game_id)
    
    if black_on_bottom is None:
        top_player, bottom_player, black_on_bottom = game.get_board_orientation()
        
    digits = '12345678'
    letters = 'abcdefgh'
    divs = []
    
    if not black_on_bottom:
        xs = reversed(range(8))
        ys = lambda: range(8)
    else:
        xs = range(8)
        ys = lambda: reversed(range(8))
        
    for x in xs:
        d = []        
        for y in ys():
            s = str(game.game.board[Coord(y,x)])
            if (x+y) % 2 == 0:
                c = 'd'
            else:
                c = 'l'
            d.append({'img': CLASSES.get(s), 'class': c, 'symbol': s, 'id': 'tile-%s%s' % (letters[y], digits[x])})            
        divs.append(d)
    
    moves = {}
    promotions = {}
    for move in game.game.board.legal_moves():
        
        pos = str(move.position)
        dests = moves.get(pos, [])
        dests.append(str(move.destination))
        moves[pos] = dests
        if move.promote:
            key = '%s-%s' % (move.position, move.destination)
            proms = promotions.get(key, [])
            proms.append(move.promote)
            promotions[key] = proms
    moves['promotions'] = promotions
    moves_str = simplejson.dumps(moves)

    board = render_to_string('szachy/_board.html', {'moves': moves_str, 'board_divs': divs, }, RequestContext(request))
    if request.is_ajax():
        return HttpResponse(simplejson.dumps({'my_move': True, 'chessboard': board, 'moves': moves, 'moves_list': get_moves(game)}))
    return board

@facebookdj.require_login()
def game(request, game_id):
    game = get_object_or_404(Game, id=game_id)
    
    top_player, bottom_player, black_on_bottom = game.get_board_orientation()
     
    me = FBUser.objects.get_current()
    my_move = (me.id == game.current_move) 
    ongoing = game.is_ongoing    
    if not ongoing and not game.state == Game.STATE_CREATED:
        return HttpResponseRedirect(reverse('game_result', kwargs=dict(game_id=game_id)))
    if black_on_bottom:
        top_side, bottom_side = Game.PLAYER_WHITE, Game.PLAYER_BLACK
    else:
        bottom_side, top_side  = Game.PLAYER_WHITE, Game.PLAYER_BLACK
    
    form = MoveForm()
    
    board = get_chessboard(request, game_id, black_on_bottom)
    
    return render_to_response('szachy/game.html', {'game': game, 'board': board, 'moves_list': get_moves(game), 'ongoing': ongoing, 'uid': int(request.graph.uid), 'top_player': top_player, 'bottom_player': bottom_player, 'my_move': my_move, 'form': form, 'game_id': game_id, 'top_side': top_side, 'bottom_side': bottom_side}, context_instance=RequestContext(request))

@facebookdj.require_login()
def game_result(request, game_id):
    game = get_object_or_404(Game, id=game_id)
    me = FBUser.objects.get_current()
    
    board = get_chessboard(request, game_id)

    return render_to_response('szachy/game_result.html', {'game': game, 'me': me, 'board': board, 'moves_list': get_moves(game)}, RequestContext(request))
    

@facebookdj.require_login()
def my_move_ajax(request, game_id):
    game = get_object_or_404(Game, id=game_id)
        
    me = int(request.graph.uid)  
    my_move = (me == game.current_move)
    
    ongoing = game.is_ongoing    
    if not ongoing and not game.state == Game.STATE_CREATED:
        return HttpResponse(simplejson.dumps({'my_move': False, 'ongoing': False, 'redirect': reverse('game_result', kwargs=dict(game_id=game_id))}))
    
    if my_move:
        return get_chessboard(request, game_id)
    return HttpResponse(simplejson.dumps({'my_move': False, 'ongoing': True}))
    

@facebookdj.require_login()
def accept_invitation(request, opponent_id):
    try:
        g = Game.objects.get(Q(p1__id=100000448407296)|Q(p2__id=100000448407296), state=Game.STATE_CREATED)
    except Game.DoesNotExist:
        raise Http404()

    return HttpResponseRedirect(reverse('game', kwargs={'game_id': g.id})) 

@facebookdj.require_login()
def invite(request):
    return render_to_response('szachy/invite.html', {'player': request.graph.uid, 'site': Site.objects.get_current() }, context_instance=RequestContext(request))
